package com.nami.pchat.application.chat;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import com.google.protobuf.ByteString;
import com.nami.gate.external.basic.bo.ConnectedUserBO;
import com.nami.gate.external.basic.cache.user.UserDeviceRel;
import com.nami.gate.external.basic.event.EventPublisher;
import com.nami.gate.external.basic.event.enums.EventType;
import com.nami.gate.external.basic.event.factory.EventFactory;
import com.nami.gate.external.basic.event.model.CommonEvent;
import com.nami.im.network.model.enums.DownMsgErrorCode;
import com.nami.im.network.model.message.v2.Message;
import com.nami.pchat.c2c.PrivateChatFacade;
import com.nami.pchat.c2c.request.PrivateChatCmd;
import com.nami.pchat.domain.gateway.UserGateway;
import com.nami.pchat.domain.service.CacheMsgDomainService;
import com.nami.pchat.domain.service.PrivateChatDomainService;
import com.nami.transport.proto.codec.ImMessages;
import com.nami.transport.proto.codec.MqTransMsg;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.json.utils.JsonUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 单聊
 *
 * @date 2025-02-13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PrivateChatFacadeImpl implements PrivateChatFacade {

    private final UserGateway userGateway;
    private final CacheMsgDomainService cacheMsgDomainService;
    private final PrivateChatDomainService privateChatDomainService;
    private final EventPublisher eventPublisher;

    @Override
    public void execute(PrivateChatCmd cmd) {
        TimeInterval timer = DateUtil.timer();
        if (cmd.getTimestamp() == null) {
            return;
        }

        ConnectedUserBO sender = cmd.getSender();
        Message message = cmd.getMessage();
        log.info("[c2c] 收到客户端【{}】发送的单聊消息, 消息体：{}",
            sender.getUserId(), message.getMsgContent());

        if (privateChatDomainService.validateParamsNull(message)) {
            eventPublisher.publish(assembleDispatcherEvent(sender, message,
                DownMsgErrorCode.REQUEST_PARAMS_ERROR));
            log.warn("[c2c] 校验消息失败, 丢失核心参数: msg:{}", message.getMsgContent());
            return;
        } // end judge if

        Map<String, UserDeviceRel> userMap = userGateway.mapOfUsers(sender.getAppKey(),
            List.of(message.getSenderId(), message.getTargetId()));
        final UserDeviceRel senderUser = userMap.get(sender.getUserId());
        final UserDeviceRel recvUser = userMap.get(message.getTargetId());
        if (privateChatDomainService.checkUserParamError(sender, senderUser,
            recvUser, message)) {
            return;
        }

        privateChatDomainService.fillParamForThisMessage(sender.getAppKey(),
            message);

        // 幂等
        if (cacheMsgDomainService.checkIdempotent(senderUser.getAppKey(),
            senderUser.getUserId(), message.getClientUid())) {
            log.warn("[c2c] 已丢弃客户端【{}】 clientMsgId={}的重复消息：{}",
                senderUser.getNick(),
                message.getClientUid(), message.getMsgContent());
            return;
        } // end check repeat msg if

        log.info("[c2c] 已加载相关信息到消息, 【{}】向用户【{}】说：{}",
            senderUser.getNick(), recvUser.getNick(), message.getMsgContent());

        // notifyNewMessageToRecipient
        privateChatDomainService.publishMessageEvent(cmd.getQos(), sender, message);
        log.info("[c2c] 【{}】向用户【{}】发送的单聊消息.处理完毕. use:{}ms",
            senderUser.getNick(), recvUser.getNick(), timer.interval());
    }

    private CommonEvent assembleDispatcherEvent(ConnectedUserBO sender,
                                                Message message,
                                                DownMsgErrorCode downMsgErrorCode) {

        MqTransMsg.TransUser senderUser = MqTransMsg.TransUser.newBuilder()
            .setAppKey(sender.getAppKey())
            .setUserId(sender.getUserId())
            .setPlatform(sender.getPlatform())
            .setConnectId(sender.getConnectId())
            .setInstanceId(sender.getInstanceId())
            .build();

        MqTransMsg.Logic2DispatchBody logic2DispatchBody = MqTransMsg.Logic2DispatchBody.newBuilder()
            .setSender(senderUser)
            .setMessage(ByteString.copyFromUtf8(JsonUtils.toJsonString(message)))
            .setSuccess(Boolean.FALSE)
            .setErrCode(downMsgErrorCode.getCode())
            .setErrMessage(downMsgErrorCode.getMsg())
            .build();
        return EventFactory.newEvent(EventType.SEND_DISPATCHER, logic2DispatchBody.toByteArray());
    }

    private ImMessages.DownMsg toDownMsg(Message message) {
        ImMessages.DownMsg downMsg = ImMessages.DownMsg.newBuilder()
            .setClientUid(message.getClientUid())
            .setMsgId(message.getMsgId())
            .setMsgContent(ByteString.copyFromUtf8(message.getMsgContent()))
            .setMsgTime(message.getMsgTime())
            .setPlatform(message.getPlatform())
            .setChannelType(ImMessages.ChannelType.Private)
            .setSenderId(message.getSenderId())
            .setTargetId(message.getTargetId())
            .setMsgSeqNo(message.getMsgSeqNo())
            .setMsgType(message.getMsgType())
            .build();
        return downMsg;
    }


}
